/*
    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.
 */
package erwiki.api.providers;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

import org.elwiki_data.AttachmentContent;
import org.elwiki_data.PageAttachment;
import org.elwiki_data.WikiPage;

import erwiki.api.exceptions.ProviderException;

/**
 * Defines an attachment provider - a class which is capable of saving binary data as attachments.
 * <P>
 * The difference between this class and WikiPageProvider is that there PageProviders handle Unicode
 * text, whereas we handle binary data. While there are quite a lot of similarities in how we handle
 * things, many providers can really use just one. In addition, since binary files can be really
 * large, we rely on Input/OutputStreams.
 */
public interface AttachmentProvider extends WikiProvider {

	/**
	 * Put new attachment data.
	 *
	 * @param wikiPage   Wiki page is owned of specified attachment.
	 * @param attContent Attachment data to add new data to.
	 * @param attName    Attachment data name.
	 * @param data       The stream from which the provider should read the data
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void putAttachmentData(WikiPage wikiPage, AttachmentContent attContent, String attName, InputStream data)
			throws ProviderException;

	/**
	 * Get attachment data.
	 *
	 * @param atchContent The attachment content.
	 * @return An InputStream which you contains the raw data of the object. It's your responsibility to
	 *         close it.
	 * @throws ProviderException If the attachment content cannot be found.
	 * @throws IOException       If the attachment content cannot be opened.
	 */
	FileInputStream getAttachmentData(AttachmentContent atchContent) throws ProviderException, IOException;

	/**
	 * Lists all attachments attached to a page.
	 *
	 * @param page The page to list the attachments from.
	 * @return A collection of Attachment objects. May be empty, but never null.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	List<PageAttachment> listAttachments(WikiPage page) throws ProviderException;

	/**
	 * Lists changed attachments since given date. Can also be used to fetch a list of all pages.
	 * <P>
	 * This is different from WikiPageProvider, where you basically get a list of all pages, then sort
	 * them locally. However, since some providers can be more efficient in locating recently changed
	 * files (like any database) than our non-optimized Java code, it makes more sense to fetch the
	 * whole list this way.
	 * <P>
	 * To get all files, call this with Date(0L);
	 *
	 * @param timestamp List all files from this date onward.
	 * @return A List of Attachment objects, in most-recently-changed first order.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	List<PageAttachment> listAllChanged(Date timestamp) throws ProviderException;

	/**
	 * Возвращает метаданные о содержимом вложения.
	 *
	 * @param atchId  Идентификатор присоединения.
	 * @param version Требуемая версия. Необязательный параметр.
	 * @return
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	public AttachmentContent getAttachmentContentById(String atchId, int... version) throws ProviderException;

	/**
	 * Возвращает метаданные о содержимом вложения.
	 *
	 * @param page    The parent page
	 * @param name    The name of the attachment
	 * @param version The version of the attachment (it's okay to use WikiPage.LATEST_VERSION to find
	 *                the latest one)
	 * @return An attachment object
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	AttachmentContent getAttachmentContent(WikiPage page, String name, int... version) throws ProviderException;

	/**
	 * Returns version history. Each element should be an Attachment.
	 *
	 * @param att The attachment for which to find the version history for.
	 * @return A List of Attachment objects.
	 */
	List<AttachmentContent> getVersionHistory(PageAttachment att);

	/**
	 * Removes a specific version from the repository. The implementations should really do no more
	 * security checks, since that is the domain of the AttachmentManager. Just delete it as efficiently
	 * as you can.
	 *
	 * @since 2.0.19.
	 * @param att Attachment to be removed. The version field is checked, and thus only that version is
	 *            removed.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void deleteVersion(PageAttachment att) throws ProviderException;

	/**
	 * Returns the attachment corresponding to the attachment ID.
	 *
	 * @param attachmentId ID of the required attachment.
	 * @return PageAttachment or <code>null</code>.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	PageAttachment getAttachmentById(String attachmentId) throws ProviderException;

	/**
	 * Удаляет прикрепление конкретной версии.
	 * <p>
	 * Реализация действительно не должна обеспечивать дополнительную проверку безопасности, поскольку
	 * это задача AttachmentManager. </br>
	 * Просто удалить его как можно эффективнее. Также следует удалить все вспомогательные файлы и
	 * каталоги, относящиеся к этому вложению, ЕСЛИ они были созданы этим провайдером.
	 *
	 * @param att Прикрепление для удаления.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void deleteAttachmentContent(AttachmentContent att) throws ProviderException;

	/**
	 * Removes the page attachment from the repository.</br>
	 * Return operation status: =true - attachment removed successfully; =false - something went wrong.
	 *
	 * @param attachmentId ID to delete the specified attachment.
	 * @return result of the operation. True/False.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	boolean deleteAttachmentById(String attachmentId) throws ProviderException;

	/**
	 * Removes the page attachment from the repository.</br>
	 * Return operation status: =true - attachment removed successfully; =false - something went wrong.
	 *
	 * @param attachment The attachment to delete.
	 * @return result of the operation. True/False.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	boolean deleteAttachment(PageAttachment attachment) throws ProviderException;

	/**
	 * Move all the attachments for a given page so that they are attached to a new page.
	 *
	 * @param oldParent Name of the page we are to move the attachments from.
	 * @param newParent Name of the page we are to move the attachments to.
	 * @throws ProviderException если что-то пошло не так, как ожидалось.
	 */
	void moveAttachmentsForPage(String oldParent, String newParent) throws ProviderException;

}
